//!Cow
// 直译为奶牛！ Cow 是一个枚举类型，通过 use std::borrow::Cow; 引入。它的定义是 Clone-on-write，即写时克隆。本质上是一个智能指针
// 。
//写时复制（Copy on Write）技术是一种程序中的优化策略，多应用于读多写少的场景。主要思想是创建对象的时候不立即进行复制，
// 而是先引用（借用）原有对象进行大量的读操作，只有进行到少量的写操作的时候，才进行复制操作，将原有对象复制后再写入。
// 这样的好处是在读多写少的场景下，减少了复制操作，提高了性能。

//
// 它有两个可选值：
//
// Borrowed，用于包裹对象的引用（通用引用）；
// Owned，用于包裹对象的所有者；

//Cow 提供
//
// 对此对象的不可变访问（比如可直接调用此对象原有的不可变方法）；
// 如果遇到需要修改此对象，或者需要获得此对象的所有权的情况，Cow 提供方法做克隆处理，并避免多次重复克隆

//它有以下几个要点需要掌握：
//
// Cow<T> 能直接调用 T 的不可变方法，因为 Cow 这个枚举，实现了 Deref；
// 在需要写 T 的时候，可以使用 .to_mut() 方法得到一个具有所有权的值的可变借用；
// 注意，调用 .to_mut() 不一定会产生克隆；如果没有数据的所有权，则复制拥有后再返回可变引用；
// 在已经具有所有权的情况下，调用 .to_mut() 有效，但是不会产生新的克隆；
// 多次调用 .to_mut() 只会产生一次克隆。
// 在需要写 T 的时候，可以使用 .into_owned() 获取一个拥有所有权的对象（区别与引用），如果当前是借用，则发生复制，创建新的所有权对象，如果已拥有所有权，则转移至新对象。
// 如果之前 Cow 中的值是借用状态，调用此操作将执行克隆；
// 本方法，参数是self类型，它会“吃掉”原先的那个对象，调用之后原先的对象的生命周期就截止了，在 Cow 上不能调用多次；
use std::borrow::{Cow, Borrow};
#[test]
pub fn cow_demo1(){
    let mut cow: Cow<[i32]> = Cow::Owned(vec![1, 2, 3]);

    let p = cow.to_mut();
    p.push(23);
    for i in cow.iter() {
        println!("{}", i);
    }

    let mut v =cow.into_owned(); //cow失效
    v.push(2);
    for i in v.iter() {
        println!("{}", i);
    }
}
//去掉空格
fn remove_spaces(input: &str) -> Cow<str> {
    if input.contains(' ') {
        let mut buf = String::with_capacity(input.len());

        for c in input.chars() {
            if c != ' ' {
                buf.push(c);
            }
        }

        return Cow::Owned(buf); //用于包裹对象的所有者；
    }

    return Cow::Borrowed(input); //用于包裹对象的引用（通用引用）；
}
#[test]
pub fn cow_demo2(){
    let s = "helloworld";
    let mut c = remove_spaces(s);
    println!("{}", c); //helloworld

    let c = c.to_mut();
    c.push_str("ol");
    println!("{}", c);
    println!("{}", s);
}

//取绝对值
fn abs_all(input: &mut Cow<[i32]>) {
    for i in 0..input.len() {
        let v = input[i];
        if v < 0 {
            input.to_mut()[i] = -v; //如果没有数据的所有权，则复制拥有后再返回可变引用；
        }
    }

    println!("value: {:?}", input);
}

#[test]
pub fn cow_demo3(){
    // 只读，不写，没有发生复制操作
    let a = [0, 1, 2];
    let mut input = Cow::from(&a[..]);
    abs_all(&mut input);
    assert_eq!(input, Cow::Borrowed(a.as_ref()));

    // 写时复制， 在读到-1的时候发生复制
    let b = [0, -1, -2];
    let mut input = Cow::from(&b[..]);
    abs_all(&mut input);
    assert_eq!(input, Cow::Owned(vec![0,1,2]) as Cow<[i32]>);

    // 没有写时复制，因为已经拥有所有权
    let mut input = Cow::from(vec![0, -1, -2]);
    abs_all(&mut input);
    assert_eq!(input, Cow::Owned(vec![0,1,2]) as Cow<[i32]>);


    println!("{:?}", a); //[0, 1, 2]
    println!("{:?}", b); //[0, -1, -2]
    println!("{:?}", input); // [0, 1, 2]

}
